# Convert image
#
# Copyright (C) 2010 Yotam Medini <yotam.medini@gmail.com>
#
# This file is part of Gupicasa.
#
# Gupicasa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Gupicasa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gupicasa.  If not, see <http://www.gnu.org/licenses/>.


import sys
import Image
# import Image.ExifTags
import pyexiv2

import debug

def copy_metadata(ifn, ofn, override={}):
    "Copy EXIF data from ifn to ofn, with override dictionary"

    i_metadata = pyexiv2.ImageMetadata(ifn)
    o_metadata = pyexiv2.ImageMetadata(ofn)
    i_metadata.read()
    o_metadata.read()
    i_metadata.copy(o_metadata, exif=True, iptc=True, xmp=True)
    # debug.log("o_metadata=%s" % str(o_metadata))
    # debug.log("dir(o_metadata)=%s" % str(dir(o_metadata)))
    # debug.log("o_metadata.exif_keys=%s" % str(o_metadata.exif_keys))
    for k,v  in override.items():
        if v is not None:
            try:
                o_metadata[k] = v
            except Exception, e:
                debug.log("Failed [%s] := %s. %s" % (k, v, e))
        # else if o_metadata.
        elif k in o_metadata.exif_keys:
            debug.log("Deleting key=%s" % k)
            del o_metadata[k]

    o_metadata.write()


# Notes.
# + (From PIL documentaion):
#   For each pixel (x, y) in the output image, the new value is taken
#   from a position (a x + b y + c, d x + e y + f) in the input image.
# + Y grows down.

_rot_quad_matrices = [
    [ 1,  0, 0,  # Identity
      0,  1, 0],
    [ 0, -1, 0,  # CCW 90deg
      1,  0, 0],
    [-1,  0, 0,  # CCW 180deg
      0, -1, 0],
    [ 0,  1, 0,  # CCW 270deg
     -1,  0, 0]
]


def convert(ifn, ofn, wh, rotquad, meta_override={}):
    """Convert image file <ifn> to <ofn>.
    Scaling to (wh[0],wh[1]).
    Rotating counter-clockwise rotquad x 90-degrees
    """

    global _rot_quad_matrices
    err = None
    im = Image.open(ifn)
    debug.log("size=%s, wh=%s, rotquad=%d |meta_override|=%d" %
              (str(im.size), str(wh), rotquad, len(meta_override)))
    matrix = _rot_quad_matrices[rotquad][:]
    h = 1./2. # Avoid blank side line caused by internal rounding
    shift_quads = ((0,              0),
                   (im.size[0] - h, 0),
                   (im.size[0] - h, im.size[1] - h),
                   (0,              im.size[1] - h))
    shift_quad = shift_quads[rotquad]

    row = 0
    for xy in (0, 1):
        a = float(im.size[xy]) / float(wh[xy])
        matrix[row + 0] *= a
        matrix[row + 1] *= a
        matrix[row + 2] = shift_quad[xy]
        row += 3
    new_size = wh if rotquad % 2 == 0 else (wh[1], wh[0])

    imnew = im.transform(new_size, Image.AFFINE, matrix)
    del im
    try:
        imnew.save(ofn, "JPEG") # Should catch possible exception
    except Exception, e:
        err = str(e)
    del imnew
    if err is None:
        try:
            copy_metadata(ifn, ofn, meta_override)
        except Exception, e:
            err = str(e)
    return err;


if __name__ == '__main__':

    import datetime
    import string
    import sys


    def safe_int(s):
        try:
            ret = int(s)
        except:
            ret = None
        return ret


    def usage():
        sys.stderr.write("""
Usage:  %s <geo> <quad> <input-jpeg> <output-jpeg>
Where
  <geo>  = <width>x<height>   # scaling pre-rotation
  <quad> = 0,1,2,3  for counter-clockwise rotation of {0,90,180,270} degrees
"""[1:] % sys.argv[0])
        sys.exit(1)


    if len(sys.argv) != 5:
        usage()
    wh = tuple(map(safe_int, sys.argv[1].split('x')))
    rotquad = safe_int(sys.argv[2])
    ifn = sys.argv[3]
    ofn = sys.argv[4]
    if len(wh) != 2 or None in wh or rotquad is None:
        usage()
    dt_maker =  datetime.datetime(datetime.MINYEAR, 1, 1, 0, 0, 0)
    extra_metadata = {"Exif.Photo.DateTimeDigitized": dt_maker.utcnow() ,
                      "Exif.Photo.PixelXDimension": wh[0],
                      "Exif.Photo.PixelYDimension": wh[1]
                      }
    if rotquad > 0:
        extra_metadata["Exif.Image.Orientation"] = None

    convert(ifn, ofn, wh, rotquad, extra_metadata)
    sys.exit(0)
